package com.pandora.credit.mongo.service.impl;

import com.pandora.common.util.*;
import com.pandora.credit.dto.request.CustomerReportRequest;
import com.pandora.credit.dto.response.CustomerReportResponse;
import com.pandora.credit.dto.response.H5ReportResponse;
import com.pandora.credit.entity.Customer;
import com.pandora.credit.enums.ReportTypeEnum;
import com.pandora.credit.enums.ServiceTypesEnum;
import com.pandora.credit.exception.*;
import com.pandora.credit.exception.auth.AuthorizationTokenInvalidException;
import com.pandora.credit.exception.customer.CustomerNotFoundException;
import com.pandora.credit.mongo.dao.H5ReportDao;
import com.pandora.credit.mongo.entity.*;
import com.pandora.credit.mongo.service.H5ReportService;
import com.pandora.credit.service.CustomerService;
import org.apache.http.client.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author developer
 */
@Service
public class H5ReportServiceImpl implements H5ReportService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final String WM = "WM";
    private static final String OP = "OP";
    private static final String TR = "TR";
    @Autowired
    private H5ReportDao h5ReportDao;
    @Autowired
    private CustomerService customerService;

    @Value("${h5.report.address}")
    private String h5ReportAddress;

    public void save(H5Report h5Report) {
        h5ReportDao.insert(h5Report);
    }

    @Override
    public H5ReportResponse queryH5Report(String reportId) {
        if (StringUtils.isEmpty(reportId) || !StringUtils.isStrToLong(reportId)) {
            logger.info("no report id");
            throw new InvalidRequestException();
        }
        H5Report h5Report;
        try {
            h5Report = h5ReportDao.selectById(new Long(reportId));
        } catch (Exception e) {
            logger.error("Get from mongo error!", e);
            throw new DbMongoReadException();
        }
        if (h5Report == null) {
            logger.info("no report in mongo");
            throw new ReportNotExistedException();
        }
        H5ReportResponse h5ReportResponse = new H5ReportResponse();
        h5ReportResponse.setH5Report(h5Report);
        return h5ReportResponse;
    }

    @Override
    public List<H5Report> queryByCusType(long customerId, String type) {
        return h5ReportDao.selectByCusType(customerId, type);
    }

    @Override
    public CustomerReportResponse queryCustomerReports(CustomerReportRequest req) {
        CustomerReportCriteria crc = checkRequest(req);
        List<H5Report> h5Reports = h5ReportDao.selectCustomerReports(crc);
        CustomerReportResponse crr = getCustomerReportResponse(h5Reports, crc);
        return crr;
    }

    @Override
    public void saveH5Report(String report, String inputType) {
        String type = getReportType(inputType);
        logger.info("Pandora report {} is coming.", type);
        ConvertReportFormatFactory formatFactory = ConvertReportFormatFactory.getInstance();
        AbstractReport reportObject = formatFactory.getReportObject(type, report);
        if(reportObject == null) {
            logger.info("Pandora report {} is pushed with bad data.", type);
            throw new InvalidRequestException();
        }

        saveReport(type, reportObject, formatFactory);
    }

    private void saveReport(String type, AbstractReport reportObject, ConvertReportFormatFactory formatFactory) {
        //get report type code
        int reportTypeCode = getReportTypeCode(type);

        //get MetaData, new Report by dealing the original reportData under different Format
        AbstractReportAfterFormat format = formatFactory.createReportFormat(reportTypeCode);
        if (format == null) {
            logger.error("no format tool for the type: {}",type);
            throw new NotFoundException();
        }
        format.formatReport(reportObject);
        Customer cus = getCustomerByMobile(format.getMetaData().getMobile());
        if (cus == null) {
            logger.info("no customer for the  mobile: {}" + format.getMetaData().getMobile());
            throw new CustomerNotFoundException();
        }
        saveH5Report(format.getMetaData(), format.getReport(), type, cus.getId());
    }

    private String getReportType(String type) {
        String reportType;
        try {
            reportType = type.split("\\?")[0];
        } catch (Exception e) {
            logger.error("error type : {}",type,e);
            throw new ParameterErrorException("type参数错误");
        }
        if (VerifyUtil.isEmpty(reportType)) {
            logger.error("type is empty");
            throw new ParameterErrorException("type参数不可为空！");
        }
        return reportType.toUpperCase();
    }

    private CustomerReportCriteria checkRequest(CustomerReportRequest req) {
        Integer length = 0;
        if (!StringUtils.isEmpty(req.getLength())) {
            length = new Integer(req.getLength());
        }

        String inputType = req.getType();
        if (StringUtils.isEmpty(inputType)) {
            logger.info("no type for the report");
            throw new InvalidRequestException();
        }
        Integer pageLength = (length == 0) ? Constants.H5_REPORT_DEFAULT_PAGE_LENGTH : length;
        String type = inputType.toUpperCase();
        Long nextId = 0L;
        if(!StringUtils.isEmpty(req.getNextId())) {
            nextId = new Long(req.getNextId());
        }

        String mobile = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.AUTHORIZATION_TOKEN_KEY,
                        req.getAuthorizationToken()));
        if (VerifyUtil.isEmpty(mobile)) {
            logger.info("no mobile");
            throw new AuthorizationTokenInvalidException();
        }

        Customer acu = customerService.getByMobile(mobile);
        if (acu == null) {
            logger.info("can not find customer by the mobile:{}", mobile);
            throw new AuthorizationTokenInvalidException();
        }
        Long customerId = acu.getId();
        CustomerReportCriteria crc = new CustomerReportCriteria(customerId, type, nextId, pageLength);
        return crc;
    }

    private CustomerReportResponse getCustomerReportResponse(List<H5Report> h5Reports, CustomerReportCriteria crc) {
        int h5ReportsLen = h5Reports.size();
        long nextId = 0;
        int pageLength = crc.getPageLength();
        if (h5ReportsLen > 0 && h5ReportsLen > pageLength) {
            nextId = h5Reports.get(pageLength).getId();
            h5Reports.remove(pageLength);
        }

        List<CustomerReport> crs = new ArrayList<>();
        for (H5Report h5Report : h5Reports) {
            long h5ReportId = h5Report.getId();
            String h5ReportType = h5Report.getType();
            String h5ReportMobile = h5Report.getMobile();
            if (h5ReportId == 0 || VerifyUtil.isEmpty(h5ReportType) || VerifyUtil.isEmpty(h5ReportMobile)) {
                continue;
            }
            String createdTime = h5Report.getCreatedTime();
            ReportMetaData rmd = h5Report.getMetaData();
            String url = "";
            String type = crc.getType();
            String title = getTitle(type, rmd, h5ReportMobile);
            url = getUrl(type, h5ReportId);
            crs.add(new CustomerReport(title, url, createdTime));
        }
        CustomerReportResponse crr = new CustomerReportResponse();
        crr.setCustomerReports(crs);
        crr.setNextId((nextId == 0 ? "" : (nextId+"")));
        return crr;
    }

    private String getTitle(String type, ReportMetaData rmd, String h5ReportMobile) {
        String title = "";
        if (type.equals(ServiceTypesEnum.getServiceType(WM).getValue())) {
            if (rmd != null) {
                WmReportMetaData rmd2 = (WmReportMetaData) rmd;
                title = StringUtils.getStrParam("%s的%s报告",
                        String.valueOf(h5ReportMobile), String.valueOf(rmd2.getWmType()));
            }
        }
        if (type.equals(ServiceTypesEnum.getServiceType(OP).getValue())) {
            title = StringUtils.getStrParam("%s的运营商报告", String.valueOf(h5ReportMobile));
        }
        if (type.equals(ServiceTypesEnum.getServiceType(TR).getValue())) {
            title = StringUtils.getStrParam("%s的滴滴报告", String.valueOf(h5ReportMobile));
        }
        return title;
    }

    private String getUrl(String type, long h5ReportId) {
        logger.info("h5 report address is " + h5ReportAddress);
        return StringUtils.getStrParam("http://%s%s?type=%s&report_id=%s",
                String.valueOf(h5ReportAddress), String.valueOf(Constants.H5_REPORT_URL),
                String.valueOf(type), String.valueOf(h5ReportId));
    }

    private void saveH5Report(ReportMetaData metaData, AbstractReport report,
                              String type, long id) {
        H5Report h5Report = new H5Report();
        try {
           // h5Report = new H5Report();
            h5Report.setId(metaData.getReportId());
            h5Report.setCreatedTime(DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
            h5Report.setCustomerId(id);
            h5Report.setMobile(metaData.getMobile());
            h5Report.setType(type);
            h5Report.setReport(report);
            h5Report.setMetaData(metaData);
            this.save(h5Report);
            logger.info("H5 write into mongo...! the customer id is {}",id);
        } catch (Exception e) {
            logger.error("Write into mongo error!, H5 content is " + JsonUtil.toString(h5Report),e);
            throw new DbMongoSaveException();
        }

    }

    private Customer getCustomerByMobile(String mobile) {
        try{
            Customer cus = customerService.getByMobile(mobile);
            return cus;
        } catch(Exception e) {
            logger.info("error running when look for customer by the mobile: {} ", mobile);
            throw new CustomerNotFoundException();
        }
    }

    private int getReportTypeCode(String reportType) {
        ServiceTypesEnum ste = ServiceTypesEnum.getServiceType(reportType);
        String serviceType;
        int reportTypeCode = -1;
        if (ste != null) {
            serviceType = ste.getValue();
            ReportTypeEnum rte = ReportTypeEnum.getReportType(serviceType);
            if (rte != null) {
                reportTypeCode = rte.getValue();
            }
        }

        if (reportTypeCode < 0) {
            logger.info("no related type code");
            throw new ParameterErrorException("type参数错误");
        }
        logger.info("H5 type: " + reportTypeCode);
        return reportTypeCode;
    }

}
